﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using KL.UFrame.Core.Configuration;
using KL.UFrame.Core.Exception;
using KL.UFrame.Core.Result;
using KL.UFrame.Data.Entities;
using KL.UFrame.Data.Models.Account;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Practices.Unity;

namespace KL.UFrame.Data.Business.Account
{
    /// <summary>
    /// 用户账户相关业务逻辑
    /// By：杨超
    /// </summary>
    public class AccountBusiness:BusinessBase,IAccountBusiness
    {
        private IK9ApplicationUserManagerProvider _applicationUserManagerHelper;

        #region 构造函数

        public AccountBusiness()
        {
            
        }

        [InjectionConstructor]
        public AccountBusiness(IK9ApplicationUserManagerProvider userManagerHelper)
        {
            _applicationUserManagerHelper = userManagerHelper;
        }

        #endregion

        #region UserManager

        private UserManager<ApplicationUser> _userManager;

        public UserManager<ApplicationUser> UserManager
        {
            get
            {
                if (_userManager == null)
                {
                    _userManager = _applicationUserManagerHelper.GetApplicationUserManager();
                }
                else
                {
                    try
                    {
                        //_userManager在Dispose后没有变为null，原因待查
                        var temp = _userManager.ClaimsIdentityFactory;
                    }
                    catch (ObjectDisposedException)
                    {
                        _userManager = _applicationUserManagerHelper.GetApplicationUserManager();

                    }
                }
                return _userManager;
            }
        }

        #endregion

        #region RoleManager

        private RoleManager<IdentityRole> RoleManager => new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(Db));

        #endregion

        #region 缓存Key

        private static string GetUserInfoCacheKey(string userName) => "UserInfo_"+userName;

        private static string GetUserRolesCacheKey(string userId) => "UserRoles_" + userId;

        #endregion

        #region 个人账户

        /// <summary>
        /// 通过用户名和密码查询用户
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        /// <returns>成功返回true，否则返回false</returns>
        public async Task<ApplicationUser> FindUserAsync(string userName, string password)
        {
            return await UserManager.FindAsync(userName, password);
        }

        /// <summary>
        /// 根据用户名获取用户信息
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public async Task<UserInfoModel> GetUserInfoByNameAsync(string userName)
        {
            var cacheKey = GetUserInfoCacheKey(userName);
            var userInfo =Cache.Get<UserInfoModel>(cacheKey);

            if (userInfo == null)
            {
                var user = await UserManager.FindByNameAsync(userName);
                if (user == null)
                {
                    throw new ResultException(-404,$"用户名为{userName}的用户不存在");
                }
                userInfo = new UserInfoModel
                {
                    Id=user.Id,
                    Email = user.Email,
                    EmailConfirmed = user.EmailConfirmed,
                    LockoutEnabled = user.LockoutEnabled,
                    Nickname = string.IsNullOrEmpty(user.Nickname)? user.UserName:user.Nickname,
                    Phone = user.PhoneNumber,
                    UserName = user.UserName,
                    WechatOpenId = user.WechatOpenId,
                    HeadImageUrl = string.IsNullOrEmpty(user.HeadImageUrl)? AppConfiguration.DefaultUserHeadImageUrl: AppConfiguration.GetAbsoluteUrl(user.HeadImageUrl)
                };

                Cache.Add(cacheKey, userInfo);
                Cache.Expire(cacheKey,TimeSpan.FromHours(2));
            }
            return userInfo;
        }

        /// <summary>
        /// 根据用户名获取用户角色组
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<string[]> GetUserRolesAsync(string userId)
        {
            var cacheKey = GetUserRolesCacheKey(userId);

            var roles = Cache.Get<string[]>(cacheKey);

            if (roles == null)
            {
                var rolesList = await UserManager.GetRolesAsync(userId);
                if (rolesList != null)
                {
                    roles = rolesList.ToArray();
                    Cache.Add(cacheKey, roles);
                    Cache.Expire(cacheKey,TimeSpan.FromHours(2));
                }
            }
            
            return roles ?? new string []{};
        }

        /// <summary>
        /// 注册用户
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> CreateUserAsync(UserRegisterModel model)
        {
            //if (Validate(model.UserName, model.Code))
            //{
            //    throw new ResultException(-500, "验证码不正确或已失效");
            //}

            var user = new ApplicationUser
            {
                UserName = model.UserName,
                EmailConfirmed = false,
                Email = model.Email,
                RegisterTime = DateTime.Now
            };
           var result=await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded) return true;
            throw new ResultException(-500,"创建用户失败，"+string.Join(";", result.Errors));
        }
        

        /// <summary>
        /// 找回密码
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> SetPassordAsync(ResetPasswordModel model)
        {
            if (Validate(model.UserName, model.Code))
            {
                throw new ResultException(-500, "验证码不正确或已失效");
            }
            var user = await UserManager.FindByNameAsync(model.UserName);
            if (user == null)
            {
                throw new ResultException(-500,"用户尚未注册");
            }
            var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
            var result = await UserManager.ResetPasswordAsync(user.Id, token, model.Password);
            if (result.Succeeded)
            {
                if (user.LockoutEnabled)
                {
                    await UserManager.SetLockoutEnabledAsync(user.Id, false);
                    await UserManager.ResetAccessFailedCountAsync(user.Id);
                }
                return true;
            }
            throw new ResultException(-500, "找回密码失败");
        }


        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<bool> ChangePassordAsync(ChangePasswordModel model)
        {
            var user = await UserManager.FindByNameAsync(model.UserName);
            if (user == null)
            {
                throw new ResultException(-500, "用户尚未注册");
            }
            var result = await UserManager.ChangePasswordAsync(user.Id, model.Password, model.NewPassword);
            if (result.Succeeded)
            {
                return true;
            }
            if (result.Errors.Any(a => a.Contains("密码不正确")))
            {
                throw new ResultException(-500, "原密码不正确");
            }
            throw new ResultException(-500, "修改密码失败");
        }

        /// <summary>
        /// 修改昵称
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<int> ChangeNicknameAsync(string userId, string name)
        {
            var user = await Db.Users.FirstOrDefaultAsync(a=>a.Id==userId);
            if(user==null) throw new ResultException(-404,"用户不存在");
            user.Nickname = name;
            Db.Entry(user).State= EntityState.Modified;
            var result = await Db.SaveChangesAsync();
            if (result > 0)
            {
                var key = GetUserInfoCacheKey(user.UserName);
                Cache.Remove(key);
            }
            return result;
        }


        #endregion

        #region 系统账户管理

        /// <summary>
        /// 后台创建用户
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<string> CreateUserFromBackendAsync(UserRegisterModel model)
        {
            var user = new ApplicationUser
            {
                UserName = model.UserName,
                PhoneNumber = model.UserName,
                PhoneNumberConfirmed = true,
                RegisterTime = DateTime.Now
            };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await Db.SaveChangesAsync();
                return user.Id;
            }
            throw new ResultException(-500, "创建用户失败，" + string.Join(";", result.Errors));
        }

        public async Task<string> CreateRoleAsync(string roleName)
        {
            if (await RoleManager.RoleExistsAsync(roleName))
            {
                throw new ResultException(-500,"角色已存在");
            }
            var role = new IdentityRole(roleName);
            var result = await RoleManager.CreateAsync(role);
            if (result.Succeeded) return role.Id;
            throw new ResultException(-500,result.Errors.First());
        }

        /// <summary>
        /// 分页查找用户列表
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public async Task<ResultMessage<List<UserInfoModel>>> GetAllAsync(string phone, int pageIndex, int pageSize)
        {
            var query = Db.Users.AsNoTracking()
                 .Where(a => string.IsNullOrEmpty(phone) || a.UserName == phone);

            var count = await query.CountAsync();
            var result = await query.Select(user => new UserInfoModel
            {
                Id = user.Id,
                Email = user.Email,
                EmailConfirmed = user.EmailConfirmed,
                LockoutEnabled = user.LockoutEnabled,
                Nickname = user.Nickname,
                Phone = user.PhoneNumber,
                UserName = user.UserName,
                WechatOpenId = user.WechatOpenId,
                RegisterTime = user.RegisterTime
            })
                .OrderByDescending(a => a.RegisterTime)
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();
            return new ResultMessage<List<UserInfoModel>>(result, count);
        }

        public async Task<List<UserRoleModel>> GetRolesAsync(string userId)
        {
            var roles = await RoleManager.Roles.ToListAsync();
            var userRoles = await UserManager.GetRolesAsync(userId);
            var query = from r in roles
                join ur in userRoles on r.Name equals ur
                    into result
                from role in result.DefaultIfEmpty()
                select new UserRoleModel
                {
                    Name = r.Name,
                    Authorized = role != null
                };
            return query.ToList();
        }

        /// <summary>
        /// 切换用户锁定状态
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<bool> ToggleLockAsync(string userId)
        {
            var user = await Db.Users.SingleOrDefaultAsync(a => a.Id == userId);
            if (user == null) throw new ResultException(-500, "用户不存在");
            if (user.LockoutEnabled)
            {
                user.LockoutEnabled = false;
                user.LockoutEndDateUtc = null;
                user.AccessFailedCount = 0;
            }
            else
            {
                user.LockoutEnabled = true;
                user.LockoutEndDateUtc = DateTime.Now;
            }
            Db.Entry(user).State = EntityState.Modified;
            return await Db.SaveChangesAsync() > 0;
        }

        public async Task<bool> ToggleRoleAsync(string userId, string role)
        {
           var roles=await UserManager.GetRolesAsync(userId);
            IdentityResult result;
            var add = true;
            if (roles.Contains(role))
            {
                result = await UserManager.RemoveFromRoleAsync(userId, role);
                add = false;
            }
            else
            {
                result = await UserManager.AddToRoleAsync(userId, role);
            }
            if (result.Succeeded) return add;

            throw new ResultException(-500,result.Errors.First());
        }
        #endregion

        /// <summary>
        /// 校验短信验证码
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        private bool Validate(string phone,string code)
        {
            var key = AppConfiguration.GetValidationKey(phone);
            var cacheCode = Cache.Get<string>(key);
            if (string.IsNullOrEmpty(cacheCode))
            {
                return false;
            }
            if (cacheCode == code)
            {
                Cache.Remove(key);
                return true;
            }
            return false;
        }


        #region IDisposable

        protected override void Dispose(bool disposing)
        {
            if (disposing && _userManager != null)
            {
                _userManager.Dispose();
                _userManager = null;
            }
            base.Dispose(disposing);
        }

        #endregion
    }
}